package com.lihao.walkers.surfaceview;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import com.lihao.walkers.utils.Constants;

import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.os.Build;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.WindowManager;

/**
 * 可视控件的回调。
 * @author lihao
 */
public class MainViewCallback implements Callback {

	/** 上下文。 */
	private Context mContext = null;

	/** 后置摄像头。 */
	private Camera mBackCamera = null;

	/** 预览宽度。 */
	private int mPreviewWidth = -1;

	/** 预览高度。 */
	private int mPreviewHeight = -1;

	/** 方向。 */
	private int mRotation = -1;

	/** 取景框的控制器。 */
	private SurfaceHolder mHolder = null;

	/** 标记是否已经开始预览。 */
	private boolean mIsPreviewStart = false;

	/**
	 * 回调的构造方法。
	 * @param context 上下文。
	 * @param previewWidth 预览宽度。
	 * @param previewHeight 预览高度。
	 * @param holder 取景框的控制器。
	 */
	public MainViewCallback(Context context, int previewWidth, int previewHeight,
							SurfaceHolder holder, int rotation){
		this.mContext = context;
		this.mPreviewWidth = previewWidth;
		this.mPreviewHeight = previewHeight;
		this.mHolder = holder;
		this.mRotation = rotation;
		initPreviewResolution();
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		mBackCamera = openCamera();
		initBestPreviewResolution();
		try {
			mBackCamera.setPreviewDisplay(mHolder); // 通过给定的holder控制的surfaceView来取景。
		} catch (IOException e) {
			e.printStackTrace();
		}
		mBackCamera.startPreview(); // 开始预览。
		mIsPreviewStart = true;
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
							   int height) {

	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		if(mBackCamera != null && mIsPreviewStart){
			mBackCamera.stopPreview();
			mBackCamera.release();
		}
	}

	/**
	 * 检查一下给定的预览框尺寸，如果有小于等于0的，就使用默认的尺寸。<br />
	 * 另外为了保持合理的宽高比，还要在竖屏的时候对宽和高的尺寸进行一下计算。
	 */
	private void initPreviewResolution(){
		if(mPreviewWidth <= 0 || mPreviewHeight <= 0){ // 检测是否使用默认值。
			WindowManager wm = (WindowManager) mContext.
					getSystemService(Context.WINDOW_SERVICE);
			Display display = wm.getDefaultDisplay();
			mPreviewWidth = mPreviewWidth <= 0 ? display.getWidth() : mPreviewWidth;
			mPreviewHeight = mPreviewHeight <= 0 ? display.getHeight() : mPreviewHeight;
		}
		if(mPreviewWidth < mPreviewHeight){ // 预览的时候若是竖屏，则交换宽与高。
			mPreviewWidth = mPreviewWidth + mPreviewHeight;
			mPreviewHeight = mPreviewWidth - mPreviewHeight;
			mPreviewWidth = mPreviewWidth - mPreviewHeight;
		}
	}

	/**
	 * 初始化摄像头。
	 * @return 摄像头对象。
	 */
	@SuppressLint("NewApi")
	private Camera openCamera(){
		Camera camera = null;
		if(Build.VERSION.SDK_INT >= 9){
			CameraInfo backCameraInfo = new CameraInfo();
			int backCameraID = -1;
			int cameraCount = Camera.getNumberOfCameras(); // 获得摄像头的个数。
			int i = 0;
			for (; i < cameraCount; i++) {
				Camera.getCameraInfo(i, backCameraInfo);
				if(CameraInfo.CAMERA_FACING_BACK == backCameraInfo.facing){ // 检测到后置摄像头。
					backCameraID = i; // 获得后置摄像头的ID。
					break;
				}
			}
			if(backCameraID >= 0){
				camera = Camera.open(backCameraID); // 打开摄像头。
				setCameraDisplayOrientation(camera, backCameraInfo, true);
				return camera;
			}
		}
		if(Build.VERSION.SDK_INT < 9 || camera == null){ // 低版本SDK或者上边初始化失败，直接打开摄像头。
			camera = Camera.open();
			setCameraDisplayOrientation(camera, null, false);
		}
		return camera;
	}

	/**
	 * 设置后置摄像头的方向。<br />
	 * <b>这个方法不能在预览的过程中调用，在预览之前或者之后调用都可以。</b>
	 * @param camera 需要进行调整的摄像头。
	 * @param cameraInfo 摄像头的信息。
	 * @param useNewMethod 是否使用新的调整方向的方法。
	 */
	@SuppressLint("NewApi")
	private void setCameraDisplayOrientation(Camera camera,CameraInfo cameraInfo,
											 boolean useNewMethod) {
		if(useNewMethod){
			int degrees = 0; // 需要旋转的角度。
			switch (mRotation) {
				case Surface.ROTATION_0:
					degrees = 0;
					break;
				case Surface.ROTATION_90:
					degrees = 90;
					break;
				case Surface.ROTATION_180:
					degrees = 180;
					break;
				case Surface.ROTATION_270:
					degrees = 270;
					break;
			}
			int result = (cameraInfo.orientation - degrees + 360) % 360;
			camera.setDisplayOrientation(result);
		} else {
			camera.setDisplayOrientation(Constants.DEFAULT_DEGREE);
		}
	}

	/**
	 * 获得最佳预览分辨率。
	 * @return 最佳预览分辨率。
	 */
	private void initBestPreviewResolution(){
		int screenSize = mPreviewWidth * mPreviewHeight;
		Parameters parameters = mBackCamera.getParameters();
		List<Size> supportedSizes = parameters.getSupportedPreviewSizes();
		if (supportedSizes == null) {
			useDefaultResolution();
			return;
		}
		int optionalPreviewWidth = -1;
		int optionalpreviewHeight = -1;
		int diff = -1;
		Iterator<Size> it = supportedSizes.iterator();
		while(it.hasNext()){
			Size supportedResolution = it.next();
			int supportedWidth = supportedResolution.width;
			int supportedHeight = supportedResolution.height;
			if(supportedWidth < supportedHeight){
				supportedWidth = supportedWidth + supportedHeight;
				supportedHeight = supportedWidth - supportedHeight;
				supportedWidth = supportedWidth - supportedHeight;
			}
			if(supportedWidth == mPreviewWidth
					&& supportedHeight == mPreviewHeight){
				useDefaultResolution();
				return;
			}
			int supportedSize = supportedWidth * supportedHeight;
			int currentDiff = Math.abs(supportedSize - screenSize);
			diff = diff == -1 ? currentDiff : diff;
			if(currentDiff < diff){
				diff = currentDiff;
				optionalPreviewWidth = supportedWidth;
				optionalpreviewHeight = supportedHeight;
			}
		}
		try{
			parameters.setPreviewSize(optionalPreviewWidth, optionalpreviewHeight);
			mBackCamera.setParameters(parameters);
		} catch(Exception e){
			e.printStackTrace();
		}
	}

	/**
	 * 使用给定的默认分辨率进行预览。
	 */
	private void useDefaultResolution(){
		try{
			Parameters parameters = mBackCamera.getParameters();
			parameters.setPreviewSize(mPreviewWidth, mPreviewHeight);
			mBackCamera.setParameters(parameters);
		} catch(Exception e){
			e.printStackTrace();
		}
	}
}
